@testable import hello
import VaporTesting
import Testing
import Fluent

@Suite("App Tests with DB", .serialized)
struct helloTests {
    private func withApp(_ test: (Application) async throws -> ()) async throws {
        let app = try await Application.make(.testing)
        do {
            try await configure(app)
            try await app.autoMigrate()
            try await test(app)
            try await app.autoRevert()
        } catch {
            try? await app.autoRevert()
            try await app.asyncShutdown()
            throw error
        }
        try await app.asyncShutdown()
    }
    
    @Test("Test Hello World Route")
    func helloWorld() async throws {
        try await withApp { app in
            try await app.testing().test(.GET, "users", afterResponse: { res async in
                #expect(res.status == .ok)
            })
        }
    }
    
    @Test("Getting all the Users")
    func getAllUsers() async throws {
        try await withApp { app in
            let sampleUsers = [User(name: "李四", age: 20), User(name: "赵五", age: 22)]
//            try await sampleUsers.create(on: app.db)
            try await app.testing().test(.GET, "users", afterResponse: { res async throws in
                #expect(res.status == .ok)
                
            })
        }
    }
    
    @Test("Creating a User")
    func createUser() async throws {
        let newDTO = UserDTO(name: "张三",age: 18)
        try await withApp { app in
            try await app.testing().test(.POST, "users", beforeRequest: { req in
                try req.content.encode(newDTO)
            }, afterResponse: { res async throws in
                let models = try await User.query(on: app.db).all()
                let filterModels = models.filter { user in
                    return user.name == newDTO.name
                }
                let array = filterModels.map({$0.name})
                #expect(res.status == .ok)
                #expect(array == [newDTO.name])
            })
        }
    }
    @Test("Deleting a User")
    func deleteUser() async throws {
        let testUsers = [User(name: "王六", age: 20), User(name: "刘老大", age: 18)]
        
        try await withApp { app in
//            try await testUsers.create(on: app.db) 
            try await app.testing().test(.DELETE, "users\(testUsers[0].name)", afterResponse: { res async throws in
                #expect(res.status == .noContent)
//                let model = try await User.find(testUsers[0].id, on: app.db)
//                #expect(model == nil)
            })
        }
    }
}

extension UserDTO: Equatable {
    public static func == (lhs: Self, rhs: Self) -> Bool {
        lhs.id == rhs.id && lhs.name == rhs.name && lhs.age == rhs.age
    }
}